import { useControlController, useNamespace } from '@ibiz-template/vue3-util';
import {
  defineComponent,
  PropType,
  resolveComponent,
  h,
  VNode,
  reactive,
  ComponentPublicInstance,
  watch,
} from 'vue';
import {
  IPanelContainer,
  IPanelField,
  IPanelItem,
  IPanelTabPanel,
  IViewLayoutPanel,
} from '@ibiz/model-core';
import { ViewLayoutPanelController } from './view-layout-panel.controller';
import './view-layout-panel.scss';

/**
 * 绘制面板成员
 *
 * @author lxm
 * @date 2023-02-07 05:58:43
 * @param {IPanelItem} panelItem
 * @param {ViewLayoutPanelController} c
 * @returns {*}  {(VNode | undefined)}
 */
function renderPanelItem(
  panelItem: IPanelItem,
  c: ViewLayoutPanelController,
  ins: ComponentPublicInstance,
): VNode | null {
  if ((panelItem as IPanelField).hidden) {
    return null;
  }
  const { providers, panelItems } = c;
  const provider = providers[panelItem.id!];
  if (!provider) {
    return (
      <div>
        暂未支持的面板项: {panelItem.id} - {panelItem.itemType}
      </div>
    );
  }
  const component = resolveComponent(provider.component);
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  let children: any;
  // 占位类型成员填充外部对应的插槽。
  if (panelItem.itemType === 'CTRLPOS' && ins.$slots[panelItem.id!]) {
    children = (): Array<VNode | null> => {
      return ins.$slots[panelItem.id!]!();
    };
  } else if (
    panelItem.itemType === 'TABPANEL' &&
    (panelItem as IPanelTabPanel).panelTabPages?.length
  ) {
    children = (): Array<VNode | null> => {
      return (panelItem as IPanelTabPanel).panelTabPages!.map(child => {
        return renderPanelItem(child, c, ins);
      });
    };
  } else if ((panelItem as IPanelContainer).panelItems?.length) {
    children = (): Array<VNode | null> => {
      return (panelItem as IPanelContainer).panelItems!.map(child => {
        return renderPanelItem(child, c, ins);
      });
    };
  }

  return h(
    component,
    {
      modelData: panelItem,
      controller: panelItems[panelItem.id!],
      key: panelItem.id,
    },
    children,
  );
}

/**
 * 视图布局面板组件
 */
export const ViewLayoutPanelControl = defineComponent({
  name: 'IBizViewLayoutPanelControl',
  props: {
    modelData: {
      type: Object as PropType<IViewLayoutPanel>,
      required: true,
    },
    context: { type: Object as PropType<IContext>, required: true },
    params: { type: Object as PropType<IParams>, default: () => ({}) },
    data: Object as PropType<IData>,
  },
  setup(props) {
    const c = useControlController(
      (...args) => new ViewLayoutPanelController(...args),
    );
    const ns = useNamespace(`control-${c.model.controlType!.toLowerCase()}`);

    watch(
      () => {
        props.data!;
      },
      () => {
        if (props.data) {
          c.setInputData(props.data);
          c.load();
        }
      },
      {
        immediate: true,
      },
    );

    c.evt.on('onCreated', () => {
      // 面板成员state响应式
      const keys = Object.keys(c.panelItems);
      keys.forEach(key => {
        const panelItem = c.panelItems[key];
        panelItem.state = reactive(panelItem.state);
      });
    });

    return { c, ns };
  },
  render() {
    const { state, model } = this.c;

    return (
      <iBizControlBase controller={this.c}>
        <iBizRow class={this.ns.b('content')} layout={{ layout: 'FLEX' }}>
          {state.isCreated &&
            (this.$slots.default
              ? this.$slots.default({
                  panelItems: this.c.panelItems,
                })
              : model.rootPanelItems?.map(panelItem => {
                  const subC = this.c.panelItems[panelItem.id!];
                  // 视图布局面板的子默认布局改成flex
                  // eslint-disable-next-line no-param-reassign
                  panelItem.layoutPos!.layout = 'FLEX';
                  return (
                    <iBizCol layoutPos={panelItem.layoutPos} state={subC.state}>
                      {renderPanelItem(panelItem, this.c, this)}
                    </iBizCol>
                  );
                }))}
        </iBizRow>
      </iBizControlBase>
    );
  },
});
